#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>

#define MAX_STACK_DEPTH 127
#define TASK_COMM_LEN 16
#define MAX_CPUS 128

struct {
    __uint(type, BPF_MAP_TYPE_STACK_TRACE);
    __uint(key_size, sizeof(u32));
    __uint(value_size, MAX_STACK_DEPTH * sizeof(u64));
    __uint(max_entries, 16384);
} stack_traces SEC(".maps");

// 修改为 PERF_EVENT_ARRAY 类型
struct {
    __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
    __uint(key_size, sizeof(u32));
    __uint(value_size, sizeof(u32));
    __uint(max_entries, MAX_CPUS);
} events SEC(".maps");

struct event {
    u32 pid;
    u32 tid;
    u64 stack_id;
    char comm[TASK_COMM_LEN];
};

SEC("perf_event")
int profile_cpu(struct bpf_perf_event_data *ctx) {
    struct event e = {};
    u64 id = bpf_get_current_pid_tgid();
    u32 pid = id >> 32;
    u32 tid = (u32)id;

    // 忽略内核线程
    if (pid == 0)
        return 0;

    e.pid = pid;
    e.tid = tid;
    bpf_get_current_comm(e.comm, sizeof(e.comm));
    
    // 获取用户空间堆栈ID
    e.stack_id = bpf_get_stackid(&ctx->regs, &stack_traces, 
                     BPF_F_USER_STACK | BPF_F_FAST_STACK_CMP);

    // 使用 perf_event_output 输出事件
    bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &e, sizeof(e));
    return 0;
}

char LICENSE[] SEC("license") = "GPL";